#ifndef INTEGRAL_ENGINES_SAFE_H_
#define INTEGRAL_ENGINES_SAFE_H_
/*
 * integral_engines.h
 *
 *  Created on: Mar 19, 2013
 *      Author: drewlewis
 */

#include <chemistry/molecule/molecule.h>
#include <chemistry/qc/basis/integral.h>
#include <chemistry/qc/basis/split.h>
#include <tiled_array.h>
#include "../Global.h"

namespace sc {

    // Thread safe integral engines accessor
    template <typename EngType>
    class IntegralEnginePool {

        public:
            // Constructor
            IntegralEnginePool(const Ref<EngType> &engine):
                prototype_(engine) {
                // Register the thread local storage key
                if (pthread_key_create(&key_, &destroy_thread_object) != 0)
                    throw std::runtime_error(
                               "IntegralEnginePool::IntegralEnginePool(): "
                               "Unable to register thread local storage key.");
            }

            // Destructor
            ~IntegralEnginePool() {
                // Unregister the thread local storage key
                pthread_key_delete(key_);
            }

            Ref<EngType> intance() const {
                Ref<EngType>* RefEngine =
                   reinterpret_cast< Ref<EngType>* >(pthread_getspecific(key_));

                if(RefEngine == NULL){

                    // Allocate new engine
                    RefEngine = new Ref<EngType>;

                    // Clone engine for this thread
                    lock_.lock(); // <<< Begin Critical Section
                        *RefEngine = prototype_->clone();
                    lock_.unlock(); // <<< End Critical Section

                    // Give new engine to thread local storage
                    pthread_setspecific(key_, RefEngine);
                }

                return *RefEngine;
            }

        private:

            // Data members
            pthread_key_t key_; // The thread local storage key
            Ref<EngType> prototype_; // Main thread group of engines for main thread
            mutable madness::Mutex lock_; //Madness lock

            // Destroy thread object
            static void destroy_thread_object(void* p) {
                delete reinterpret_cast< Ref<EngType>* >(p);
            }

            // Not allowed, do not implement
            IntegralEnginePool(const IntegralEnginePool&);
            IntegralEnginePool& operator=(const IntegralEnginePool&);

    };//IntegralEnginePool
}
#endif /* INTEGRAL_ENGINES_SAFE_H_ */
